﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

using zijian666.Converts.Abstractions;
using zijian666.Converts.Core;
using zijian666.Converts.Extensions;
using zijian666.Converts.Factory;
using zijian666.Core;
using zijian666.Core.Abstractions;

namespace zijian666.Converts;

/// <summary>
/// 超级转换器
/// </summary>
public static partial class Converts
{

    static Converts()
    {
        var factories = new List<IConvertorFactory>();
        var translators = new List<ITranslator>();
        var serializers = new StringSerializerCollection();

        foreach (var feature in FeatureManager.Gets<IFeature>())
        {
            if (feature is IConvertorFactory factory)
            {
                factories.Add(factory);
            }
            if (feature is ITranslator translator)
            {
                translators.Add(translator);
            }
            if (feature is IStringSerializer serializer)
            {
                serializers.Register(serializer);
            }
            else
            {
                var type = feature.GetType().GetGenericArguments(typeof(IConvertor<>));
                if (type is not null && type.Length == 1)
                {
                    factories.Add(new InstantiatedConvertorFactory(feature, type[0]));
                }
            }
        }

        var builder = new ConvertorBuilder(factories.ToArray());
        Settings = new ConvertSettings(builder)
        {
            StringSeparator = ",",
            Encoding = Encoding.UTF8,
            CultureInfo = CultureInfo.CurrentUICulture,
            NumberFormatInfo = NumberFormatInfo.CurrentInfo,
            StringSplitOptions = StringSplitOptions.RemoveEmptyEntries,
        };
        Settings.Translators.AddRange(translators);
        StringSerializers = serializers;
    }

    /// <summary>
    /// 全局默认转换设置
    /// </summary>
    public static ConvertSettings Settings { get; }
    /// <summary>
    /// 字符串序列化程序
    /// </summary>
    public static StringSerializerCollection StringSerializers { get; }
    /// <summary>
    /// 将 <paramref name="value"/> 转换为 <typeparamref name="T"/> 
    /// </summary>
    /// <typeparam name="T">输出类型</typeparam>
    /// <param name="value">输入值</param>
    /// <param name="settings">转换设置</param>
    public static ConvertResult<T> Convert<T>(this object? value, IConvertSettings? settings = null)
    {
        using var context = ConvertContext.CreateScope(settings.Merge(Settings));
        return context.Convert<T>(value);
    }
    /// <summary>
    /// 将 <paramref name="value"/> 转换为 <paramref name="type"/>
    /// </summary>
    /// <param name="value">输入值</param>
    /// <param name="type">输出类型</param>
    /// <param name="settings">转换设置</param>
    public static ConvertResult<object> Convert(this object? value, Type type, IConvertSettings? settings = null)
    {
        using var context = ConvertContext.CreateScope(settings.Merge(Settings));
        return context.Convert(type, value);
    }
    /// <summary>
    /// 将 <paramref name="value"/> 转换为 <typeparamref name="T"/>，如果转换失败返回 <paramref name="defaultValue"/>
    /// </summary>
    /// <typeparam name="T">输出类型</typeparam>
    /// <param name="value">输入值</param>
    /// <param name="defaultValue">转换失败返回该值</param>
    public static T? To<T>(this object? value, T? defaultValue) => Convert<T>(value, null).GetValueOrDefalut(defaultValue);
    /// <summary>
    /// 将 <paramref name="value"/> 转换为 <typeparamref name="T"/>，如果转换失败返回抛出异常
    /// </summary>
    /// <typeparam name="T">输出类型</typeparam>
    /// <param name="value">输入值</param>
    public static T? To<T>(this object? value) => Convert<T>(value, null).Value;

    /// <summary>
    /// 将 <paramref name="value"/> 转为动态类型，可使用忽略大小写的属性名称获取值
    /// </summary>
    /// <param name="value">输入值</param>
    /// <returns></returns>
    public static dynamic ToDynamic(this object? value) => value is DynamicObject and IObjectProxy ? value : To<DynamicObject>(value)!;

    /// <summary>
    /// 获取一个类型的默认值
    /// </summary>
    /// <param name="type"> </param>
    /// <returns> </returns>
    public static object? GetDefault(this Type type)
    {
        if (type is not null && type.IsValueType && Nullable.GetUnderlyingType(type) is null)
        {
            return Activator.CreateInstance(type);
        }
        return null;
    }

    /// <summary>
    /// 判断一个对象的值是否为 null 或等效于null的值
    /// </summary>
    public static bool IsNull(this object? value)
        => value switch
        {
            null => true,
            DBNull => true,
            IConvertible x => x.GetTypeCode() is TypeCode.DBNull or TypeCode.Empty,
            _ => value.Equals(null) || value.Equals(DBNull.Value),
        };

    /// <summary>
    /// 判断一个对象的值是否为空,包括null,空集合,空字符串
    /// </summary>
    public static bool IsEmpty(this object? value)
        => value switch
        {
            null => true,
            DBNull => true,
            string x => x.Length == 0,
            Array x => x.Length == 0,
            ICollection x => x.Count == 0,
            IEnumerable x => !x.Cast<object>().Any(),
            IConvertible x => x.GetTypeCode() switch
            {
                TypeCode.DBNull => true,
                TypeCode.Empty => true,
                _ => false
            },
            _ => value.Equals(null) || value.Equals(DBNull.Value),
        };

    /// <summary>
    /// 判断一个对象的值是否为连续的空白,包括null,空集合,空字符串,空白字符串,全部为null,空字符串或空白字符串的集合
    /// </summary>
    public static bool IsSerialBlank(this object? value)
        => value switch
        {
            null => true,
            DBNull => true,
            string s => string.IsNullOrWhiteSpace(s),
            IEnumerable<char> s => s.All(char.IsWhiteSpace),
            StringBuilder s => s.Length == 0 || string.IsNullOrWhiteSpace(s.ToString()),
            IEnumerable<string> s => s.All(string.IsNullOrWhiteSpace),
            IEnumerable<object> s => s.All(x => x is null),
            IEnumerable s => s.Cast<object>().All(x => x is null),
            IConvertible s => s.GetTypeCode() switch
            {
                TypeCode.DBNull => true,
                TypeCode.Empty => true,
                TypeCode.String => string.IsNullOrWhiteSpace(s.ToString(null)),
                _ => false
            },
            _ => value.Equals(null) || value.Equals(DBNull.Value),
        };

    /// <summary>
    /// 在转换默认设置中设置字符串序列化程序
    /// </summary>
    public static void SetStringSerializer(IStringSerializer serializer)
        => ((ISlot<IStringSerializer>)Settings)?.Set(serializer);
    /// <summary>
    /// 在转换默认设置中设置反射程序
    /// </summary>
    public static void SetReflectCompiler(IReflectCompiler compiler)
        => ((ISlot<IReflectCompiler>)Settings)?.Set(compiler);
    /// <summary>
    /// 获取 <seealso cref="IFormatterConverter"/> 转换器
    /// </summary>
    /// <returns></returns>
    public static IFormatterConverter GetFormatterConverter() => FormatterConverter.Instance;
    
    /// <summary>
    /// 将转换器功能设置到当前组件
    /// </summary>
    /// <param name="slot">待设置功能的组件</param>
    public static void SetFeatureFormatterConverter(this ISlot<IFormatterConverter> slot)
        => slot.Set(FormatterConverter.Instance);

}

